<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2048 - 经典版</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            color: #776e65;
        }

        .container {
            text-align: center;
            background: rgba(255, 255, 255, 0.95);
            padding: 30px;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
        }

        h1 {
            font-size: 48px;
            margin-bottom: 20px;
            color: #776e65;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
        }

        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            flex-wrap: wrap;
            gap: 20px;
        }

        .scores {
            display: flex;
            gap: 20px;
        }

        .score-box {
            background: #bbada0;
            padding: 10px 20px;
            border-radius: 8px;
            color: white;
            min-width: 100px;
        }

        .score-label {
            font-size: 14px;
            margin-bottom: 5px;
        }

        .score-value {
            font-size: 24px;
            font-weight: bold;
        }

        .controls {
            display: flex;
            gap: 10px;
        }

        button {
            background: #8f7a66;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 16px;
            transition: background 0.3s;
        }

        button:hover {
            background: #7f6a56;
        }

        .game-board {
            background: #bbada0;
            padding: 15px;
            border-radius: 10px;
            display: inline-block;
            margin: 20px 0;
        }

        .grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-template-rows: repeat(4, 1fr);
            gap: 15px;
            width: 400px;
            height: 400px;
        }

        .cell {
            background: #cdc1b4;
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 36px;
            font-weight: bold;
            transition: all 0.15s ease;
            position: relative;
        }

        .cell[data-value="2"] {
            background: #eee4da;
            color: #776e65;
        }

        .cell[data-value="4"] {
            background: #ede0c8;
            color: #776e65;
        }

        .cell[data-value="8"] {
            background: #f2b179;
            color: #f9f6f2;
        }

        .cell[data-value="16"] {
            background: #f59563;
            color: #f9f6f2;
        }

        .cell[data-value="32"] {
            background: #f67c5f;
            color: #f9f6f2;
        }

        .cell[data-value="64"] {
            background: #f65e3b;
            color: #f9f6f2;
        }

        .cell[data-value="128"] {
            background: #edcf72;
            color: #f9f6f2;
            font-size: 32px;
        }

        .cell[data-value="256"] {
            background: #edcc61;
            color: #f9f6f2;
            font-size: 32px;
        }

        .cell[data-value="512"] {
            background: #edc850;
            color: #f9f6f2;
            font-size: 32px;
        }

        .cell[data-value="1024"] {
            background: #edc53f;
            color: #f9f6f2;
            font-size: 28px;
        }

        .cell[data-value="2048"] {
            background: #edc22e;
            color: #f9f6f2;
            font-size: 28px;
        }

        .cell.new {
            animation: appear 0.2s ease;
        }

        .cell.merge {
            animation: merge 0.2s ease;
        }

        @keyframes appear {
            0% {
                transform: scale(0);
            }

            100% {
                transform: scale(1);
            }
        }

        @keyframes merge {
            0% {
                transform: scale(1);
            }

            50% {
                transform: scale(1.2);
            }

            100% {
                transform: scale(1);
            }
        }

        .game-over {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }

        .game-over.show {
            display: flex;
        }

        .game-over-content {
            background: white;
            padding: 40px;
            border-radius: 15px;
            text-align: center;
        }

        .game-over h2 {
            font-size: 36px;
            margin-bottom: 20px;
            color: #776e65;
        }

        .instructions {
            margin-top: 20px;
            font-size: 14px;
            color: #776e65;
            line-height: 1.5;
        }

        @media (max-width: 600px) {
            .container {
                padding: 20px;
                margin: 10px;
            }

            .grid {
                width: 300px;
                height: 300px;
                gap: 10px;
            }

            .cell {
                font-size: 28px;
            }

            .header {
                flex-direction: column;
                align-items: center;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>2048</h1>

        <div class="header">
            <div class="scores">
                <div class="score-box">
                    <div class="score-label">分数</div>
                    <div class="score-value" id="score">0</div>
                </div>
                <div class="score-box">
                    <div class="score-label">最高分</div>
                    <div class="score-value" id="best-score">0</div>
                </div>
            </div>

            <div class="controls">
                <button onclick="newGame()">新游戏</button>
                <button onclick="undoMove()">撤销</button>
            </div>
        </div>

        <div class="game-board">
            <div class="grid" id="grid"></div>
        </div>

        <div class="instructions">
            <p><strong>游戏规则：</strong>使用方向键移动方块，相同数字的方块相撞时会合并。</p>
            <p>目标：获得2048！</p>
        </div>
    </div>

    <div class="game-over" id="gameOver">
        <div class="game-over-content">
            <h2 id="gameOverText">游戏结束</h2>
            <p id="gameOverScore">最终分数：0</p>
            <button onclick="newGame()">再玩一次</button>
        </div>
    </div>

    <script>
        class Game2048 {
            constructor() {
                this.grid = Array(4).fill().map(() => Array(4).fill(0));
                this.score = 0;
                this.bestScore = parseInt(localStorage.getItem('2048-best-score')) || 0;
                this.moveHistory = [];
                this.init();
            }

            init() {
                this.createGrid();
                this.addRandomTile();
                this.addRandomTile();
                this.updateDisplay();
                this.setupEventListeners();
            }

            createGrid() {
                const gridElement = document.getElementById('grid');
                gridElement.innerHTML = '';

                for (let i = 0; i < 4; i++) {
                    for (let j = 0; j < 4; j++) {
                        const cell = document.createElement('div');
                        cell.className = 'cell';
                        cell.dataset.row = i;
                        cell.dataset.col = j;
                        gridElement.appendChild(cell);
                    }
                }
            }

            addRandomTile() {
                const emptyCells = [];
                for (let i = 0; i < 4; i++) {
                    for (let j = 0; j < 4; j++) {
                        if (this.grid[i][j] === 0) {
                            emptyCells.push({
                                row: i,
                                col: j
                            });
                        }
                    }
                }

                if (emptyCells.length > 0) {
                    const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
                    this.grid[randomCell.row][randomCell.col] = Math.random() < 0.9 ? 2 : 4;
                }
            }

            updateDisplay() {
                const cells = document.querySelectorAll('.cell');
                cells.forEach(cell => {
                    const row = parseInt(cell.dataset.row);
                    const col = parseInt(cell.dataset.col);
                    const value = this.grid[row][col];

                    cell.textContent = value || '';
                    cell.dataset.value = value || '';
                    cell.className = 'cell';

                    if (value > 0) {
                        cell.classList.add('new');
                    }
                });

                document.getElementById('score').textContent = this.score;
                document.getElementById('best-score').textContent = this.bestScore;
            }

            setupEventListeners() {
                document.addEventListener('keydown', (e) => {
                    if (e.key.startsWith('Arrow')) {
                        e.preventDefault();
                        this.handleMove(e.key);
                    }
                });

                // 触摸支持
                let startX, startY;
                document.addEventListener('touchstart', (e) => {
                    startX = e.touches[0].clientX;
                    startY = e.touches[0].clientY;
                });

                document.addEventListener('touchend', (e) => {
                    if (!startX || !startY) return;

                    const endX = e.changedTouches[0].clientX;
                    const endY = e.changedTouches[0].clientY;

                    const deltaX = endX - startX;
                    const deltaY = endY - startY;

                    if (Math.abs(deltaX) > Math.abs(deltaY)) {
                        if (deltaX > 0) this.handleMove('ArrowRight');
                        else this.handleMove('ArrowLeft');
                    } else {
                        if (deltaY > 0) this.handleMove('ArrowDown');
                        else this.handleMove('ArrowUp');
                    }

                    startX = startY = null;
                });
            }

            handleMove(direction) {
                const oldGrid = JSON.parse(JSON.stringify(this.grid));
                const oldScore = this.score;

                let moved = false;

                switch (direction) {
                    case 'ArrowUp':
                        moved = this.moveUp();
                        break;
                    case 'ArrowDown':
                        moved = this.moveDown();
                        break;
                    case 'ArrowLeft':
                        moved = this.moveLeft();
                        break;
                    case 'ArrowRight':
                        moved = this.moveRight();
                        break;
                }

                if (moved) {
                    this.moveHistory.push({
                        grid: oldGrid,
                        score: oldScore
                    });

                    if (this.moveHistory.length > 10) {
                        this.moveHistory.shift();
                    }

                    this.addRandomTile();
                    this.updateDisplay();

                    if (this.score > this.bestScore) {
                        this.bestScore = this.score;
                        localStorage.setItem('2048-best-score', this.bestScore);
                    }

                    if (this.checkWin()) {
                        this.showGameOver('恭喜！你赢了！', true);
                    } else if (this.isGameOver()) {
                        this.showGameOver('游戏结束！');
                    }
                }
            }

            moveLeft() {
                return this.move(row => {
                    const newRow = row.filter(cell => cell !== 0);
                    for (let i = 0; i < newRow.length - 1; i++) {
                        if (newRow[i] === newRow[i + 1]) {
                            newRow[i] *= 2;
                            this.score += newRow[i];
                            newRow.splice(i + 1, 1);
                        }
                    }
                    while (newRow.length < 4) {
                        newRow.push(0);
                    }
                    return newRow;
                });
            }

            moveRight() {
                return this.move(row => {
                    const newRow = row.filter(cell => cell !== 0);
                    for (let i = newRow.length - 1; i > 0; i--) {
                        if (newRow[i] === newRow[i - 1]) {
                            newRow[i] *= 2;
                            this.score += newRow[i];
                            newRow.splice(i - 1, 1);
                            i--;
                        }
                    }
                    while (newRow.length < 4) {
                        newRow.unshift(0);
                    }
                    return newRow;
                });
            }

            moveUp() {
                return this.move(col => {
                    const newCol = col.filter(cell => cell !== 0);
                    for (let i = 0; i < newCol.length - 1; i++) {
                        if (newCol[i] === newCol[i + 1]) {
                            newCol[i] *= 2;
                            this.score += newCol[i];
                            newCol.splice(i + 1, 1);
                        }
                    }
                    while (newCol.length < 4) {
                        newCol.push(0);
                    }
                    return newCol;
                }, true);
            }

            moveDown() {
                return this.move(col => {
                    const newCol = col.filter(cell => cell !== 0);
                    for (let i = newCol.length - 1; i > 0; i--) {
                        if (newCol[i] === newCol[i - 1]) {
                            newCol[i] *= 2;
                            this.score += newCol[i];
                            newCol.splice(i - 1, 1);
                            i--;
                        }
                    }
                    while (newCol.length < 4) {
                        newCol.unshift(0);
                    }
                    return newCol;
                }, true);
            }

            move(moveFunction, isVertical = false) {
                const oldGrid = JSON.parse(JSON.stringify(this.grid));

                if (isVertical) {
                    for (let col = 0; col < 4; col++) {
                        const column = this.grid.map(row => row[col]);
                        const newColumn = moveFunction(column);
                        for (let row = 0; row < 4; row++) {
                            this.grid[row][col] = newColumn[row];
                        }
                    }
                } else {
                    for (let row = 0; row < 4; row++) {
                        this.grid[row] = moveFunction([...this.grid[row]]);
                    }
                }

                return JSON.stringify(oldGrid) !== JSON.stringify(this.grid);
            }

            checkWin() {
                for (let i = 0; i < 4; i++) {
                    for (let j = 0; j < 4; j++) {
                        if (this.grid[i][j] === 2048) {
                            return true;
                        }
                    }
                }
                return false;
            }

            isGameOver() {
                // 检查是否有空格
                for (let i = 0; i < 4; i++) {
                    for (let j = 0; j < 4; j++) {
                        if (this.grid[i][j] === 0) {
                            return false;
                        }
                    }
                }

                // 检查是否可以合并
                for (let i = 0; i < 4; i++) {
                    for (let j = 0; j < 4; j++) {
                        const current = this.grid[i][j];
                        if ((i < 3 && this.grid[i + 1][j] === current) ||
                            (j < 3 && this.grid[i][j + 1] === current)) {
                            return false;
                        }
                    }
                }

                return true;
            }

            showGameOver(message, isWin = false) {
                document.getElementById('gameOverText').textContent = message;
                document.getElementById('gameOverScore').textContent = `最终分数：${this.score}`;
                document.getElementById('gameOver').classList.add('show');
            }

            undoMove() {
                if (this.moveHistory.length > 0) {
                    const lastMove = this.moveHistory.pop();
                    this.grid = lastMove.grid;
                    this.score = lastMove.score;
                    this.updateDisplay();
                }
            }
        }

        let game;

        function newGame() {
            document.getElementById('gameOver').classList.remove('show');
            game = new Game2048();
        }

        function undoMove() {
            if (game) {
                game.undoMove();
            }
        }

        // 初始化游戏
        newGame();
    </script>
</body>

</html>